<template>
  <div class="left-panel">
    <img
      :src="currentDeviceImage"
      alt="Device Diagram"
      class="device-image"
      @load="positionSensorDots"
    />
    <div class="sensor-dots" ref="sensorDotsContainer"></div>

    <div
      v-if="activeSensorPopupId"
      :id="`chartPopup${activeSensorPopupId}`"
      class="chart-popup"
      :style="popupStyle"
    >
      <button class="close-chart-btn" @click="closePopup">&times;</button>
      <canvas :id="`sensorChartCanvas-${activeSensorPopupId}`"></canvas>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, watch, onMounted, nextTick, onUnmounted } from 'vue'
import Chart from 'chart.js/auto' // 确保正确导入 Chart.js
import 'chartjs-plugin-annotation' // 确保导入标注插件

const props = defineProps({
  currentDevice: String,
  sensorPoints: Array, // 从 AnomalyDetectionView 接收
})

const currentDeviceImage = computed(() => {
  // 假设图片在 public/img 目录下
  return `/img/${props.currentDevice === '联醇装置' ? 'device.png' : 'device1.png'}`
})

const sensorDotsContainer = ref(null)

// ==========================================================
// 弹窗和图表相关状态及逻辑（从 SensorChartPopup.vue 整合过来）
// ==========================================================
const activeSensorPopupId = ref(null) // 存储当前打开的传感器点的完整ID（例如 'FIC1007'）
const sensorChartInstance = ref(null) // 用于存储 Chart 实例
const popupPosition = ref({ top: '0px', left: '0px' }) // 控制弹窗位置

// 计算弹窗的动态样式
const popupStyle = computed(() => ({
  top: popupPosition.value.top,
  left: popupPosition.value.left,
  display: activeSensorPopupId.value ? 'flex' : 'none', // 根据 activeSensorPopupId 控制显示
}))

/**
 * 销毁 Chart.js 实例，释放资源。
 */
const destroyChart = () => {
  if (sensorChartInstance.value) {
    sensorChartInstance.value.destroy()
    sensorChartInstance.value = null
    console.log(`LeftPanel: Chart instance for ${activeSensorPopupId.value} destroyed.`)
  }
}

/**
 * 关闭弹窗并销毁图表实例。
 */
const closePopup = () => {
  activeSensorPopupId.value = null // 关闭弹窗
  // destroyChart() 也会在 activeSensorPopupId 变化时通过 watch 触发
}

/**
 * 从后端获取传感器历史和预测数据。
 * @param {string} pointName - 传感器的点位名称。
 * @returns {Promise<Object>} 包含 labels, historicalChartData, predictedChartData 的对象。
 */
const fetchSensorData = async (pointName) => {
  try {
    console.log(`LeftPanel: Fetching data for point: ${pointName}`)

    const response = await fetch(`/api/get_point_data?point=${pointName}`)

    if (!response.ok) {
      const errorText = await response.text()
      throw new Error(
        `Failed to fetch sensor data for ${pointName}: ${response.status} ${response.statusText} - ${errorText}`,
      )
    }
    const data = await response.json()
    console.log(`LeftPanel: Received data for ${pointName}:`, data)

    if (!data.success) {
      throw new Error(
        `API returned success: false - ${data.message || 'Unknown error'} for point ${pointName}`,
      )
    }

    // 解析历史数据
    const historicalLabels = data.history.map((item) => {
      return new Date(item.datetime).toLocaleTimeString([], {
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
      })
    })
    const historicalData = data.history.map((item) => item.value)

    // 解析预测数据
    const predictedLabels = data.predict.map((item) => {
      return new Date(item.datetime).toLocaleTimeString([], {
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
      })
    })
    const predictedData = data.predict.map((item) => item.value)

    // 将历史数据和预测数据合并成适合 Chart.js 的数据结构
    const allLabels = [...historicalLabels]
    const historicalChartData = [...historicalData]
    const predictedChartData = Array(
      historicalData.length > 0 ? historicalData.length - 1 : 0,
    ).fill(null)
    if (historicalData.length > 0) {
      predictedChartData.push(historicalData[historicalData.length - 1])
    } else {
      predictedChartData.push(null)
    }

    for (let i = 0; i < predictedLabels.length; i++) {
      allLabels.push(predictedLabels[i])
      predictedChartData.push(predictedData[i])
    }

    return {
      labels: allLabels,
      historicalChartData: historicalChartData,
      predictedChartData: predictedChartData,
    }
  } catch (error) {
    console.error(`LeftPanel: Error fetching data for ${pointName}:`, error)
    return { labels: [], historicalChartData: [], predictedChartData: [] }
  }
}

/**
 * 绘制传感器数据折线图。
 */
const drawSensorChart = async (sensorIdToDraw) => {
  destroyChart() // 确保销毁旧图表实例

  const canvasId = `sensorChartCanvas-${sensorIdToDraw}` // 获取当前要绘制的Canvas ID
  const canvasElement = document.getElementById(canvasId)
  if (!canvasElement) {
    console.error(`LeftPanel: Canvas element not found for ID: ${canvasId}. Cannot draw chart.`)
    return
  }
  const ctx = canvasElement.getContext('2d')
  if (!ctx) {
    console.error(`LeftPanel: Could not get 2D context for canvasId: ${canvasId}.`)
    return
  }
  // console.log(`LeftPanel: Canvas context obtained for ${sensorIdToDraw}.`)

  const { labels, historicalChartData, predictedChartData } = await fetchSensorData(sensorIdToDraw)

  if (labels.length === 0) {
    console.warn(`LeftPanel: No data to display for sensor ${sensorIdToDraw} chart.`)
    if (ctx) {
      ctx.clearRect(0, 0, canvasElement.width, canvasElement.height)
      ctx.font = '16px Arial'
      ctx.fillStyle = '#888'
      ctx.textAlign = 'center'
      ctx.fillText('暂无数据', canvasElement.width / 2, canvasElement.height / 2)
    }
    return
  }

  const allNumericalData = [...historicalChartData, ...predictedChartData].filter(
    (v) => typeof v === 'number' && v !== null,
  )
  let minValue = allNumericalData.length > 0 ? Math.min(...allNumericalData) : 0
  let maxValue = allNumericalData.length > 0 ? Math.max(...allNumericalData) : 100

  if (minValue === maxValue) {
    minValue -= 5
    maxValue += 5
  }
  const padding = (maxValue - minValue) * 0.1

  sensorChartInstance.value = new Chart(ctx, {
    type: 'line',
    data: {
      labels: labels,
      datasets: [
        {
          label: '历史数据',
          data: historicalChartData,
          borderColor: 'rgb(54, 162, 235)',
          backgroundColor: 'rgba(54, 162, 235, 0.1)',
          borderWidth: 2,
          tension: 0.3,
          pointRadius: 0,
          fill: false,
          spanGaps: true,
        },
        {
          label: '预测数据',
          data: predictedChartData,
          borderColor: 'rgb(75, 192, 192)',
          backgroundColor: 'rgba(75, 192, 192, 0.1)',
          borderWidth: 2,
          tension: 0.3,
          pointRadius: 0,
          fill: false,
          spanGaps: true,
        },
      ],
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        title: {
          display: true,
          text: `传感器 ${sensorIdToDraw} 数据趋势`,
          font: { size: 14 },
        },
        legend: {
          display: true,
          position: 'top',
        },
      },
      scales: {
        x: {
          display: true,
          title: {
            display: true,
            text: '时间',
          },
          ticks: {
            autoSkip: true,
            maxTicksLimit: 10,
          },
        },
        y: {
          display: true,
          title: {
            display: true,
            text: '参数值',
          },
          min: minValue - padding,
          max: maxValue + padding,
        },
      },
    },
  })
}

// 监听 activeSensorPopupId 的变化来触发弹窗显示和图表绘制
watch(activeSensorPopupId, async (newSensorId, oldSensorId) => {
  if (newSensorId) {
    // 如果有新的 sensorId 被激活
    // console.log(`LeftPanel: Active popup changed to: ${newSensorId}. Attempting to show and draw.`)
    // 确保 DOM 更新，特别是 v-if 渲染的 canvas 元素
    await nextTick()
    // 此时 activeSensorPopupId 对应的 div 和 canvas 应该已经渲染到 DOM 中
    drawSensorChart(newSensorId)
  } else {
    // 如果 activeSensorPopupId 变为空，表示关闭弹窗
    console.log(`LeftPanel: Active popup changed from ${oldSensorId} to null. Destroying chart.`)
    destroyChart()
  }
})
// ==========================================================
// END 弹窗和图表相关状态及逻辑
// ==========================================================

// ==========================================================
// 传感器点位渲染和点击逻辑（保持不变或微调）
// ==========================================================
// 定义颜色映射
const COLOR_MAP = {
  main: '#DC3545', // 红色
  relative: '#FFC107', // 黄色
  other: '#6C757D', // 灰色
}

const positionSensorDots = () => {
  const deviceImage = document.querySelector('.left-panel .device-image')
  if (!deviceImage || !deviceImage.naturalWidth) {
    deviceImage.onload = positionSensorDots
    return
  }

  const imageRect = deviceImage.getBoundingClientRect()
  const leftPanelRect = deviceImage.closest('.left-panel').getBoundingClientRect()

  const imgActualLeftInPanel = imageRect.left - leftPanelRect.left
  const imgActualTopInPanel = imageRect.top - leftPanelRect.top
  const imgActualWidth = imageRect.width
  const imgActualHeight = imageRect.height

  sensorDotsContainer.value.style.position = 'absolute'
  sensorDotsContainer.value.style.left = `${imgActualLeftInPanel}px`
  sensorDotsContainer.value.style.top = `${imgActualTopInPanel}px`
  sensorDotsContainer.value.style.width = `${imgActualWidth}px`
  sensorDotsContainer.value.style.height = `${imgActualHeight}px`
  sensorDotsContainer.value.innerHTML = '' // 清空现有传感器点

  const points = props.sensorPoints // 使用 props.sensorPoints
  if (!Array.isArray(points) || points.length === 0) {
    console.warn('LeftPanel: No sensor points available for current device.')
    return
  }

  points.forEach((point) => {
    const dot = document.createElement('div')
    dot.className = 'sensor-dot'
    dot.id = `dot${point.id}` // 绿色点的ID，例如 dotFIC1001
    dot.setAttribute('data-dot-id', point.id) // 存储点位ID

    // 根据 colorCategory 设置背景颜色
    dot.style.backgroundColor = COLOR_MAP[point.category] || COLOR_MAP['other']
    // 也可以根据需要调整 box-shadow 颜色
    dot.style.boxShadow = `0 0 5px ${COLOR_MAP[point.category] || COLOR_MAP['other']}B3` // 80% 透明度

    const dotPixelLeft = (parseFloat(point.left) / 100) * imgActualWidth
    const dotPixelTop = (parseFloat(point.top) / 100) * imgActualHeight

    dot.style.top = `${dotPixelTop}px`
    dot.style.left = `${dotPixelLeft}px`

    dot.addEventListener('click', (event) => handleSensorDotClick(point.id, dot, event))
    sensorDotsContainer.value.appendChild(dot)
  })
}

const handleSensorDotClick = (dotId, dotElement, event) => {
  // 如果点击的是已经打开的弹窗，则关闭它
  if (activeSensorPopupId.value === dotId) {
    activeSensorPopupId.value = null // 关闭当前打开的弹窗
    return
  }

  // 关闭所有其他可能打开的弹窗（如果只允许一个弹窗打开）
  // 这里通过直接设置 activeSensorPopupId.value = null 来实现，watch 会处理销毁
  // 然后在 nextTick 中设置新的 activeSensorPopupId

  // 计算弹窗位置
  const leftPanel = document.querySelector('.left-panel')
  const imageRect = document.querySelector('.left-panel .device-image').getBoundingClientRect()
  const leftPanelRect = leftPanel.getBoundingClientRect()

  const imgActualLeft = imageRect.left - leftPanelRect.left
  const imgActualTop = imageRect.top - leftPanelRect.top
  const imgActualWidth = imageRect.width
  const imgActualHeight = imageRect.height

  const dotPixelLeftInImage = parseFloat(dotElement.style.left)
  const dotPixelTopInImage = parseFloat(dotElement.style.top)

  // 假设弹窗固定尺寸为 400x250px (与 .chart-popup 样式一致)
  const popupWidth = 400
  const popupHeight = 250
  const imagePadding = 10

  let topPos = imgActualTop + dotPixelTopInImage - popupHeight / 2
  let leftPos = imgActualLeft + dotPixelLeftInImage - popupWidth / 2

  // 确保弹窗在图片范围内（并留有内边距）
  if (leftPos < imgActualLeft + imagePadding) {
    leftPos = imgActualLeft + imagePadding
  }
  if (leftPos + popupWidth > imgActualLeft + imgActualWidth - imagePadding) {
    leftPos = imgActualLeft + imgActualWidth - popupWidth - imagePadding
  }
  if (topPos < imgActualTop + imagePadding) {
    topPos = imgActualTop + imagePadding
  }
  if (topPos + popupHeight > imgActualTop + imgActualHeight - imagePadding) {
    topPos = imgActualTop + imgActualHeight - popupHeight - imagePadding
  }

  // 更新弹窗位置状态
  popupPosition.value = { top: `${topPos}px`, left: `${leftPos}px` }

  // 激活新的弹窗
  activeSensorPopupId.value = dotId // 设置要打开的弹窗的 sensorId
  console.log('LeftPanel: Activating popup for sensor:', dotId, 'at position:', popupPosition.value)
}

// 监听 currentDevice 的变化，重新定位传感器点
watch(
  () => props.currentDevice,
  () => {
    activeSensorPopupId.value = null // 切换设备时关闭所有弹窗
    positionSensorDots()
  },
)

// 组件挂载时初始化
onMounted(() => {
  positionSensorDots()
  // 添加窗口大小改变监听器，刷新页面以重新定位传感器点
  let resizeTimer
  window.addEventListener('resize', () => {
    clearTimeout(resizeTimer)
    resizeTimer = setTimeout(() => {
      // 简单粗暴的刷新方式，实际项目中可能需要更精细的重绘逻辑
      // 或者只重新计算点位和弹窗位置
      location.reload()
    }, 200)
  })
})

// 组件卸载时，确保销毁 Chart 实例，防止内存泄漏
onUnmounted(() => {
  destroyChart()
})
</script>

<style scoped>
/* Left Panel 样式 */
/* .left-panel {
  flex: 3;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  padding: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  position: relative;
  min-height: 0;
}

.device-image {
  max-width: 100%;
  max-height: 100%;
  width: 100%; 
  height: 100%; 
  object-fit: cover; 
  display: block;
  border-radius: 5px;
} */

.sensor-dots {
  position: absolute;
  pointer-events: none; /* 允许点击穿透到下面的点 */
}

.sensor-dot {
  width: 35px;
  height: 35px;
  background-color: #4caf50;
  border-radius: 50%;
  position: absolute;
  transform: translate(-50%, -50%);
  cursor: pointer;
  z-index: 10;
  box-shadow: 0 0 5px rgba(0, 255, 0, 0.7);
  pointer-events: all; /* 确保点本身可点击 */
}

/* Chart Popup 样式 (从 SensorChartPopup.vue 整合过来) */
.chart-popup {
  position: absolute;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  padding: 15px;
  z-index: 20;
  width: 400px;
  height: 250px;
  /* display 属性将由 popupStyle 计算属性动态控制 */
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.chart-popup .close-chart-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  background: none;
  border: none;
  font-size: 1.5em;
  cursor: pointer;
  color: #555;
  z-index: 21;
}

.chart-popup canvas {
  width: 100% !important;
  height: 100% !important;
}
</style>
